// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.warehouse.viewers.xml;

import static org.dengues.core.IDesignerCoreService.LOOP_QUERY;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dengues.core.DenguesCorePlugin;
import org.dengues.core.components.IXMLComponent;
import org.dengues.core.components.NodePropertyParameter;
import org.dengues.core.property.EParameterFieldCategory;
import org.dengues.core.property.PropertyCellModifier;
import org.dengues.core.property.PropertyTableViewer;
import org.dengues.core.warehouse.ENodeCategoryName;
import org.dengues.model.database.DatabaseDiagram;
import org.dengues.warehouse.i18n.Messages;
import org.dengues.warehouse.viewers.wizards.NewElementWizardPage3;
import org.eclipse.core.runtime.IPath;
import org.eclipse.datatools.enablement.oda.xml.util.ui.ATreeNode;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Transform;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 2007-11-27 qiang.zhang $
 * 
 */
public class NewXmlWizardPage3 extends NewElementWizardPage3 {

    private Tree availableXmlTree;

    private TreePopulator treePopulator;

    private ATreeNode treeNode;

    private PropertyTableViewer rooXPathViewer;

    private PropertyTableViewer fieldsViewer;

    private TreeViewer treeViewer;

    private SashForm generic;

    /**
     * Qiang.Zhang.Adolf@gmail.com NewDatabaseWizardPage constructor comment.
     * 
     * @param database
     * @param isActived
     */
    public NewXmlWizardPage3(IPath path, DatabaseDiagram database, ENodeCategoryName name) {
        super(path, database, name);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getFieldsParam".
     * 
     * @return
     */
    private NodePropertyParameter getFieldsParam() {
        NodePropertyParameter rootParam = new NodePropertyParameter();
        rootParam.setName(Messages.getString("NewXmlWizardPage3.schemaFields")); //$NON-NLS-1$
        rootParam.setFieldCategory(EParameterFieldCategory.TABLE);
        rootParam.setItemDisplayNames(new String[] {
                Messages.getString("NewXmlWizardPage3.relativePath"), Messages.getString("NewXmlWizardPage3.columnName") }); //$NON-NLS-1$ //$NON-NLS-2$
        rootParam.setItemNames(new String[] { RELATIVE_XPATH, COLUMN_NAME });
        NodePropertyParameter[] itemValues = new NodePropertyParameter[2];
        NodePropertyParameter chParam = new NodePropertyParameter();
        chParam.setFieldCategory(EParameterFieldCategory.TEXT);
        chParam.setValue(""); //$NON-NLS-1$
        itemValues[0] = chParam;
        chParam = new NodePropertyParameter();
        chParam.setFieldCategory(EParameterFieldCategory.TEXT);
        chParam.setValue(""); //$NON-NLS-1$
        itemValues[1] = chParam;

        rootParam.setItemValues(itemValues);
        rootParam.setValue(new ArrayList<Map<String, Object>>());
        return rootParam;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getRootXPathParam".
     * 
     * @return
     */
    private NodePropertyParameter getRootXPathParam() {
        NodePropertyParameter rootParam = new NodePropertyParameter();
        rootParam.setName(Messages.getString("NewXmlWizardPage3.rootPath"));//$NON-NLS-1$
        rootParam.setFieldCategory(EParameterFieldCategory.TABLE);
        rootParam.setItemDisplayNames(new String[] { Messages.getString("NewXmlWizardPage3.rootPath") }); //$NON-NLS-1$
        rootParam.setItemNames(new String[] { ROOT_XPATH });
        NodePropertyParameter[] itemValues = new NodePropertyParameter[1];
        NodePropertyParameter chParam = new NodePropertyParameter();
        chParam.setFieldCategory(EParameterFieldCategory.TEXT);
        chParam.setValue("");//$NON-NLS-1$
        itemValues[0] = chParam;
        rootParam.setItemValues(itemValues);
        rootParam.setValue(new ArrayList<Map<String, Object>>());
        return rootParam;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.warehouse.viewers.wizards.NewElementWizardPage3#addListeners()
     */
    protected void addListeners() {
        generic.setBackgroundMode(SWT.INHERIT_FORCE);
        Transfer[] transfers = new Transfer[] { LocalSelectionTransfer.getTransfer() };
        treeViewer.addDragSupport(DND.DROP_MOVE | DND.DROP_LINK, transfers, new DragSourceAdapter() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.dnd.DragSourceAdapter#dragStart(org.eclipse.swt.dnd.DragSourceEvent)
             */
            @Override
            public void dragStart(DragSourceEvent event) {
                ISelection selection = treeViewer.getSelection();
                LocalSelectionTransfer.getTransfer().setSelection(selection);
                LocalSelectionTransfer.getTransfer().setSelectionSetTime(event.time & 0xFFFFFFFFL);
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.dnd.DragSourceAdapter#dragSetData(org.eclipse.swt.dnd.DragSourceEvent)
             */
            @Override
            public void dragSetData(DragSourceEvent event) {
                event.data = LocalSelectionTransfer.getTransfer().getSelection();
            }
        });
        rooXPathViewer.getTableViewer().addDropSupport(DND.DROP_MOVE | DND.DROP_LINK, transfers, new DropTargetAdapter() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.dnd.DropTargetAdapter#drop(org.eclipse.swt.dnd.DropTargetEvent)
             */
            @Override
            public void drop(DropTargetEvent event) {
                TreeSelection selection = (TreeSelection) event.data;
                ATreeNode treeNode = (ATreeNode) selection.getFirstElement();
                String absoluteXPath = treePopulator.getAbsoluteXPath(treeNode);
                TableViewer tableViewer = rooXPathViewer.getTableViewer();
                List<Map<String, Object>> list = (List<Map<String, Object>>) tableViewer.getInput();
                if (list.isEmpty()) {
                    Map<String, Object> hashMap = new HashMap<String, Object>();
                    hashMap.put(ROOT_XPATH, absoluteXPath);
                    list.add(hashMap);
                } else {
                    Map<String, Object> map = list.get(0);
                    map.put(ROOT_XPATH, absoluteXPath);
                }
                tableViewer.refresh();
                refreshAllLinks();
            }
        });
        fieldsViewer.getTableViewer().addDropSupport(DND.DROP_MOVE | DND.DROP_LINK, transfers, new DropTargetAdapter() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.dnd.DropTargetAdapter#drop(org.eclipse.swt.dnd.DropTargetEvent)
             */
            @Override
            public void drop(DropTargetEvent event) {
                List<Map<String, Object>> list2 = ((List<Map<String, Object>>) rooXPathViewer.getTableViewer().getInput());
                String rootPath = "";//$NON-NLS-1$
                if (!list2.isEmpty()) {
                    rootPath = (String) list2.get(0).get(ROOT_XPATH);
                }
                TreeSelection selection = (TreeSelection) event.data;
                TableViewer tableViewer = fieldsViewer.getTableViewer();
                List<Map<String, Object>> list = (List<Map<String, Object>>) tableViewer.getInput();
                for (Object transfer : selection.toList()) {
                    ATreeNode treeNode = (ATreeNode) transfer;
                    String absoluteXPath = treePopulator.getAbsoluteXPath(treeNode);

                    Map<String, Object> hashMap = new HashMap<String, Object>();
                    hashMap.put(RELATIVE_XPATH, absoluteXPath);
                    hashMap.put(COLUMN_NAME, treeNode.getValue().toString());
                    list.add(hashMap);
                }
                tableViewer.refresh();
                refreshAllLinks();
            }
        });
        guessBtn.addSelectionListener(new SelectionAdapter() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            @Override
            public void widgetSelected(SelectionEvent e) {
                String loopRoot = getLoopRoot();
                List<Map<String, Object>> mappings = getFields();
                List<String[]> csvRows = DenguesCorePlugin.getDefault().getDesignerCoreService().getXMLPreviewRows(getFileName(),
                        loopRoot, mappings, enCodingtext.getText());
                retieveSchema(csvRows, mappings);
            }

        });
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createBgImage".
     * 
     * @return
     */
    private Image createBgImage() {
        Image image = new Image(generic.getDisplay(), generic.getClientArea());
        // if (image != null && !image.isDisposed()) {
        // GC gc = new GC(image);
        // gc.setBackground(generic.getBackground());
        // gc.fillRectangle(generic.getClientArea());
        // gc.dispose();
        // }
        return image;
    }

    /**
     * Sets the xmlFile.
     * 
     * @param xmlFile the xmlFile to set
     */
    public void setFileName(String xmlFile) {
        super.setFileName(xmlFile);
        if (treePopulator != null) {
            treePopulator.populateTree(xmlFile, treeNode);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getProperties".
     * 
     * @return
     */
    public HashMap<String, Object> getProperties() {
        super.getProperties().put(LOOP_QUERY, getLoopRoot());
        return super.getProperties();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "refreshAllLinks".
     */
    private void refreshAllLinks() {
        Image backgroundImage = generic.getBackgroundImage();
        if (backgroundImage != null && !backgroundImage.isDisposed()) {
            backgroundImage.dispose();
        }
        Image createBgImage = createBgImage();
        GC gc = new GC(createBgImage);
        Display device = generic.getDisplay();
        gc.setForeground(device.getSystemColor(SWT.COLOR_DARK_MAGENTA));
        gc.setLineWidth(3);
        gc.setAntialias(SWT.ON);
        String loopRoot = getLoopRoot();
        if (!loopRoot.equals("")) { //$NON-NLS-1$
            TreeItem treeItem = treePopulator.getTreeItem(loopRoot);
            if (treeItem != null) {
                TableItem[] items = rooXPathViewer.getTable().getItems();
                TableItem tableItem = items[0];
                if (treeItem != null) {
                    drawTreeToTable(gc, device, treeItem, tableItem);
                }
            }
        }
        gc.setForeground(device.getSystemColor(SWT.COLOR_DARK_GREEN));
        Table table = fieldsViewer.getTableViewer().getTable();
        int itemCount = table.getItemCount();
        for (int i = 0; i < itemCount; i++) {
            TableItem tableItem = table.getItem(i);
            Map<String, String> map = (Map<String, String>) tableItem.getData();
            String absXpath = map.get(RELATIVE_XPATH);
            TreeItem treeItem = treePopulator.getTreeItem(absXpath);
            if (treeItem != null) {
                drawTreeToTable(gc, device, treeItem, tableItem);
            }
        }
        gc.dispose();
        generic.setBackgroundImage(createBgImage);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "drawTreeToTable".
     * 
     * @param gc
     * @param device
     * @param treeItem
     * @param tableItem
     */
    private void drawTreeToTable(GC gc, Display device, TreeItem treeItem, TableItem tableItem) {
        Transform transform;
        Rectangle bounds = treeItem.getBounds();
        Point nPoint = new Point(bounds.x, bounds.y);
        Point tPoint1 = nPoint;
        tPoint1 = device.map(treeItem.getParent(), generic, tPoint1);

        Rectangle bounds2 = tableItem.getBounds();
        nPoint = new Point(bounds2.x, bounds2.y);
        Point tPoint2 = nPoint;
        tPoint2 = device.map(tableItem.getParent(), generic, tPoint2);
        int x1 = tPoint1.x + bounds.width;
        int y1 = tPoint1.y + bounds.height / 2;
        int x2 = tPoint2.x;
        int y2 = tPoint2.y + bounds2.height / 2;
        transform = new Transform(device);
        transform.translate(x1, y1);
        gc.setTransform(transform);
        transform.dispose();

        Path path = new Path(device);

        path.cubicTo((x2 - x1) / 2, 0, (x2 - x1) / 2, (y2 - y1), x2 - x1, y2 - y1);

        Path path2 = new Path(device);
        // path2.moveTo(x2 - x1 - 2, (float) (y2 - y1 - 3));
        // path2.lineTo(x2 - x1 - 2, (float) (y2 - y1 + 6));
        // path2.lineTo((float) (x2 - x1 + 3 - 2), (float) (y2 - y1 + 3));
        // path2.lineTo(x2 - x1 - 2, (float) (y2 - y1 - 3));
        // path.addPath(path2);
        // System.out.println("x1:" + x1 + " y1:" + y1 + " x2:" + x2 + " y2:" + y2);
        gc.drawPath(path);
        path.dispose();
        path2.dispose();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getLoopRoot".
     * 
     * @return
     */
    private String getLoopRoot() {
        TableViewer tableViewer = rooXPathViewer.getTableViewer();
        List<Map<String, Object>> list = (List<Map<String, Object>>) tableViewer.getInput();
        String loopRoot = ""; //$NON-NLS-1$
        if (!list.isEmpty()) {
            Object object = list.get(0).get(ROOT_XPATH);
            loopRoot = object.toString();
        }
        return loopRoot;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getFields".
     * 
     * @return
     */
    private List<Map<String, Object>> getFields() {
        List<Map<String, Object>> mapping = new ArrayList<Map<String, Object>>();
        int i = 0;
        TableViewer tableViewer;
        tableViewer = fieldsViewer.getTableViewer();
        List<Map<String, Object>> mappings = (List<Map<String, Object>>) tableViewer.getInput();
        for (Map<String, Object> map : mappings) {
            Map<String, Object> map2 = new HashMap<String, Object>();
            map2.put(IXMLComponent.COLUMN_SCHEMA, "row" + i); //$NON-NLS-1$
            map2.put(QUERY, map.get(COLUMN_NAME));
            mapping.add(map2);
            i++;
        }
        return mapping;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.warehouse.viewers.wizards.NewElementWizardPage3#createMiddleContent(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected void createMiddleContent(Composite container) {
        generic = new SashForm(container, SWT.HORIZONTAL);
        GridLayout layout = new GridLayout(2, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        generic.setLayout(layout);
        GridData gridData = new GridData(GridData.FILL_BOTH);
        generic.setLayoutData(gridData);

        Group metaComposite = new Group(generic, SWT.NONE);
        layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        metaComposite.setLayout(layout);
        gridData = new GridData(GridData.FILL_BOTH);
        metaComposite.setLayoutData(gridData);
        metaComposite.setText(Messages.getString("NewXmlWizardPage3.inputFile")); //$NON-NLS-1$
        treeViewer = new TreeViewer(metaComposite, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
        availableXmlTree = treeViewer.getTree();
        gridData = new GridData(GridData.FILL_BOTH);
        availableXmlTree.setLayoutData(gridData);
        this.treePopulator = new TreePopulator(availableXmlTree);
        availableXmlTree.addControlListener(new ControlListener() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.events.ControlListener#controlMoved(org.eclipse.swt.events.ControlEvent)
             */
            public void controlMoved(ControlEvent e) {

            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.events.ControlListener#controlResized(org.eclipse.swt.events.ControlEvent)
             */
            public void controlResized(ControlEvent e) {
                refreshAllLinks();
            }

        });
        metaComposite = new Group(generic, SWT.NONE);
        layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        metaComposite.setLayout(layout);
        gridData = new GridData(GridData.FILL_BOTH);
        metaComposite.setLayoutData(gridData);
        metaComposite.setText(Messages.getString("NewXmlWizardPage3.outputSchema")); //$NON-NLS-1$
        NodePropertyParameter rootParam = getRootXPathParam();
        PropertyCellModifier cellModifier = new PropertyCellModifier() {

            /*
             * (non-Javadoc)
             * 
             * @see org.dengues.core.property.PropertyCellModifier#modify(java.lang.Object, java.lang.String,
             * java.lang.Object)
             */
            @Override
            public void modify(Object element, String property, Object value) {
                super.modify(element, property, value);
                refreshAllLinks();
            }
        };
        cellModifier.setParam(rootParam);
        rooXPathViewer = new PropertyTableViewer(metaComposite, rootParam, false);
        rooXPathViewer.getTableViewer().setCellModifier(cellModifier);
        rooXPathViewer.initTableInput();
        rooXPathViewer.setTitle(rootParam.getName());
        cellModifier.setTableViewer(rooXPathViewer.getTableViewer());

        NodePropertyParameter fieldsParam = getFieldsParam();
        cellModifier = new PropertyCellModifier() {

            /*
             * (non-Javadoc)
             * 
             * @see org.dengues.core.property.PropertyCellModifier#modify(java.lang.Object, java.lang.String,
             * java.lang.Object)
             */
            @Override
            public void modify(Object element, String property, Object value) {
                super.modify(element, property, value);
                refreshAllLinks();
            }
        };
        cellModifier.setParam(fieldsParam);
        fieldsViewer = new PropertyTableViewer(metaComposite, fieldsParam, true);
        fieldsViewer.getTableViewer().setCellModifier(cellModifier);
        fieldsViewer.initTableInput();
        fieldsViewer.setTitle(fieldsParam.getName());
        cellModifier.setTableViewer(fieldsViewer.getTableViewer());

    }
}
